package com.orange.lockscreen.server;

import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.text.TextUtils;
import android.view.View;
import android.widget.RemoteViews;

import com.android.internal.policy.impl.ExtLockScreenLoader.ExtLockScreen;
import com.orange.lockscreen.common.Constants;
import com.orange.lockscreen.common.Constants.LSWidget_Type;
import com.orange.lockscreen.common.LockScreenPreferences;
import com.orange.lockscreen.common.LockScreenUtils;
import com.orange.lockscreen.common.LogHelper;
import com.orange.lockscreen.server.LockscreenView.LockscreenCallback;
import com.orange.lswidget.ILSWidgetService;

/**
 * 
 * LockscreenService: responds to create LockscreenView and communicate with
 * Lockscreen widget service.
 * 
 */
public class LockscreenService implements LockscreenCallback {

	private static final String			TAG						= "LockscreenService";
	private static final String			LS_WIDGET_SERVICE_PKG	= "com.orange.lswidget";
	private static final String			LS_WIDGET_SERVICE_CLS	= "com.orange.lswidget.LSWidgetService";
	private static final String			ACTION_READY			= "com.orange.lswidget.system_ready";

	private static final int			HANDLE_READY			= 0;
	private static final int			HANDLE_ADD				= 1;
	private static final int			HANDLE_UPDATE			= 2;

	private static LockscreenService	sLSService				= null;
	private static Context				sContext				= null;
	private static Object				syncObj					= new Object();
	private static int					sRegisterCount			= 0;

	private Handler						mHandler				= null;
	private ILSWidgetService			mService				= null;
	private Callbacks					mCallbacks				= null;
	private LockscreenViewList			mLockscreenViewList		= null;
	private LockscreenView				mLockscreenView			= null;
	private LockscreenView				mBackupView				= null;
	private boolean						mIsCleanUp				= false;

	private BroadcastReceiver			mReceiver				= new LsServiceReceiver();
	private ServiceConnection			mServiceConnection		= new LsWidgetServiceConnection();

	class LsServiceReceiver extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {

			if (mIsCleanUp) {
				return;
			}
			String action = intent.getAction();
			if (action.equals(ACTION_READY)) {
				LogHelper.v(TAG,
						"onReceive. broadcast: LSWidget System is ready.");
				// LogHelper.d(TAG,
				// "###################### mReceiver,thread name: "
				// + Thread.currentThread().getName()
				// + ",thread id: "
				// + Thread.currentThread().getId());
				Message msg = mHandler.obtainMessage(HANDLE_READY);
				msg.sendToTarget();
			}
		}
	}

	private LockscreenService(Context context) {
		mCallbacks = new Callbacks();
		mLockscreenViewList = new LockscreenViewList();
		mHandler = new UpdateHanlder();
		LogHelper.v(TAG, "LockscreenService. create");
	}

	/**
	 * Get singleton instance of LockscreenService.
	 * 
	 * @param context
	 * @return instance of LockscreenService
	 */
	public static LockscreenService getInstance(Context context) {
		if (null == sLSService) {
			synchronized (syncObj) {
				if (null == sLSService) {
					sLSService = new LockscreenService(context);
				}
			}
		}
		if (null != context) {
			sContext = context;
		}
		return sLSService;
	}

	/**
	 * Create LockscreenView.
	 * 
	 * @param context
	 * @return
	 */
	public ExtLockScreen getLockscreenView(Context context) {
		LogHelper.v(TAG, "getLockscreenView. ");

		// init LockScreenPreferences
		LockScreenPreferences.init(context);

		// LogHelper.d(TAG,
		// "###################### getLockscreenView,thread name: "
		// + Thread.currentThread().getName() + ",thread id: "
		// + Thread.currentThread().getId());
		if (LockScreenUtils.isPackageExist(context,
				Constants.PKG_ORANGE_HOMESCREEN)) {
			String defaultHomescreen = LockScreenUtils.getDefaultHome(context);

			if (!TextUtils.isEmpty(defaultHomescreen)
					&& !defaultHomescreen
							.equals(Constants.PKG_ORANGE_HOMESCREEN)) {
				return null;
			} else {
				if (LockScreenPreferences.isUnlockPatternEnabled()
						&& LockScreenPreferences.isLockscreenDisabled()) {
					return null;
				} else {
					mBackupView = mLockscreenView = new LockscreenView(context,
							sLSService);
					if (null != sContext) {
						mIsCleanUp = false;
						IntentFilter filter = new IntentFilter();
						filter.addAction(ACTION_READY);
						if (0 == sRegisterCount) {
							sContext.registerReceiver(mReceiver, filter);
							sRegisterCount++;
						}
						// LogHelper.d(TAG,
						// "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% getLockscreenView,registerCount: "
						// + registerCount);
					}
					startLSWidgetService();
					return mLockscreenView;
				}
			}
		} else {
			return null;
		}
	}

	/**
	 * Start ls-widget service.
	 */
	void startLSWidgetService() {
		if (null == sContext) {
			return;
		}
		LogHelper.v(TAG, "startLSWidgetService. ");
		ComponentName component = new ComponentName(LS_WIDGET_SERVICE_PKG,
				LS_WIDGET_SERVICE_CLS);
		Intent intent = new Intent();
		intent.setComponent(component);
		sContext.startService(intent);
	}

	/**
	 * Connect ls-widget service.
	 */
	void connectLSWidgetService() {
		if (null == sContext) {
			return;
		}
		LogHelper.v(TAG, "connectLSWidgetService. ");
		ComponentName component = new ComponentName(LS_WIDGET_SERVICE_PKG,
				LS_WIDGET_SERVICE_CLS);
		Intent intent = new Intent();
		intent.setComponent(component);
		boolean ret = sContext.bindService(intent, mServiceConnection,
				Context.BIND_AUTO_CREATE);
		if (ret) {
			LogHelper.v(TAG, "connectLSWidgetService. success");
		} else {
			LogHelper.v(TAG, "connectLSWidgetService. fail");
		}
	}

	/**
	 * Disconnect with ls-widget service.
	 */
	void disconnectLSWidgetService() {
		if (null == sContext || null == mService) {
			return;
		}
		LogHelper.v(TAG, "disconnectLSWidgetService. ");
		sContext.unbindService(mServiceConnection);
		mService = null;
	}

	/**
	 * Load ls-widget list from service.
	 */
	void loadLSWidgetList() {
		LogHelper.v(TAG, "loadLSWidgetList. ");
		if (null != mService) {
			try {
				AppWidgetProviderInfo info = null;
				RemoteViews remoteViews = null;
				LockscreenViewData viewData = null;
				boolean hasContent = true;
				int[] list = mService.getInstalledProviderType();
				if (null != list && list.length > 0) {
					for (int type : list) {
						if (type != LSWidget_Type.TYPE_INVALID) {
							info = mService.getProviderInfoByType(type);
							remoteViews = mService.getLSWidgetView(type);
							hasContent = mService
									.isLSWidgetViewHasContent(type);
							viewData = new LockscreenViewData();
							viewData.type = type;
							viewData.data = remoteViews;
							viewData.info = info;
							viewData.hasContent = hasContent;
							mLockscreenViewList.add(viewData);
						} else {
							LogHelper
									.e(TAG,
											"loadLSWidgetList. LSWidget has TYPE_INVALID");
						}
					}
				} else {
					LogHelper.v(TAG, "loadLSWidgetList. count = 0");
				}
			} catch (RemoteException e) {
				LogHelper.e(TAG, "loadLSWidgetList. ");
			}
		}

		Message msg = mHandler.obtainMessage(HANDLE_ADD);
		msg.sendToTarget();
	}

	/**
	 * Start to listen ls-widget service.
	 */
	void startListeningLSWidgetService() {
		LogHelper.v(TAG, "startListeningLSWidgetService. ");
		if (null != mService) {
			try {
				mService.startListening(mCallbacks);
			} catch (RemoteException e) {
				LogHelper.e(TAG, "startListeningLSWidgetService. ", e);
			}
		}
	}

	/**
	 * Stop listenning ls-widget service.
	 */
	void stopListeningLSWidgetService() {
		LogHelper.v(TAG, "stopListeningLSWidgetService. ");
		if (null != mService) {
			try {
				mService.stopListening();
			} catch (RemoteException e) {
				LogHelper.e(TAG, "stopListeningLSWidgetService. ", e);
			}
		}
	}

	/**
	 * Add wigets into LSWidgetHostView.
	 */
	void addLSWidgetView() {
		LogHelper.v(TAG, "addLSWidgetView. ");
		if (null == mLockscreenView && null != mBackupView) {
			LogHelper.v(TAG, "addLSWidgetView. mLockscreenView is null");
			mLockscreenView = mBackupView;
		}
		if (null != mLockscreenView) {
			mLockscreenView.post(new Runnable() {
				@Override
				public void run() {
					LockscreenViewData data = null;
					LSWidgetHostView hostView = null;
					int N = mLockscreenViewList.size();
					LogHelper.v(TAG, "run. LockscreenViewList.size()=" + N);
					for (int i = 0; i < N; i++) {
						data = mLockscreenViewList.getItem(i);
						boolean enabled = LockScreenPreferences
								.getEnabledByViewType(data.type);
						if (enabled) {
							hostView = new LSWidgetHostView(mLockscreenView
									.getContext(), data.type);
							hostView.setAppWidget(0, data.info);
							hostView.updateAppWidget(data.data);
							data.host = hostView;
							mLockscreenView.addWidgetView(hostView);
							mLockscreenView.setWidgetMoveable(data.type,
									data.hasContent);
							LogHelper.v(TAG, "run. add WidgetView[type=0x"
									+ Integer.toHexString(data.type)
									+ "] into LS slat");
						}
					}
				}
			});
		}

		mBackupView = null;
	}

	/**
	 * Update hostview when widget has changed.
	 * 
	 * @param viewType
	 *            widget type
	 */
	void updateLSWidgetView(int viewType) {
		LogHelper.v(TAG,
				"updateLSWidgetView. update LSWidget View, viewType=[0x"
						+ Integer.toHexString(viewType) + "]");
		final int type = viewType;
		if (null != mLockscreenView) {
			mLockscreenView.post(new Runnable() {
				@Override
				public void run() {
					LockscreenViewData data = mLockscreenViewList.get(type);
					if(null != data){
						LogHelper.d(TAG, "************************* updateLSWidgetView,RemoteView id: " + data.data);
					}
					if(Constants.LSWidget_Type.TYPE_EVENT == type){
						if(null != data){
							LogHelper.d("hand", "************************* updateLSWidgetView,RemoteView id: " + data.data
									+ " ,data.hasContent: " + data.hasContent);
						}
					}
					
					if (null != data && null != data.host) {
//						LogHelper.d(TAG, "##################### null != data.data " + (null != data.data)
//								+ " data.hasContent:" + (data.hasContent));
						if (null != data.data) {
							//add for fix bug with handscent receive msg
							if(!data.hasContent && Constants.LSWidget_Type.TYPE_EVENT == type ){
//								data.host.removeAllViews();
								data.host.updateAppWidget(null);
							}
							data.host.updateAppWidget(data.data);
						}
						mLockscreenView
								.setWidgetMoveable(type, data.hasContent);
					} else {
						LogHelper.v(TAG,
								"updateLSWidgetView type is not in the list.");
					}
				}
			});
		}
	}

	@Override
	public void unLock() {

	}

	@Override
	public void cleanUp() {
		// LogHelper.v(TAG,
		// "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% cleanUp. registerCount: "
		// + registerCount);

		if (null != sContext && sRegisterCount > 0) {
			try {
				sContext.unregisterReceiver(mReceiver);
			} catch (Exception e) {
				LogHelper.e(TAG, "cleanUp. ", e);
			}
			sRegisterCount--;
		}
		// LogHelper.d(TAG, "###################### cleanUp,thread name: "
		// + Thread.currentThread().getName() + ",thread id: "
		// + Thread.currentThread().getId());
		// comment by gaoge 2011-08-30 ,for fix bug
		// if (null != mHandler) {
		// mHandler.removeMessages(HANDLE_READY);
		// mHandler.removeMessages(HANDLE_ADD);
		// mHandler.removeMessages(HANDLE_UPDATE);
		// }
		stopListeningLSWidgetService();
		disconnectLSWidgetService();
		mLockscreenViewList.removeAll();
		mLockscreenView = null;
		mIsCleanUp = true;
	}

	private class LsWidgetServiceConnection implements ServiceConnection {
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mService = ILSWidgetService.Stub.asInterface(service);
			if (null != mService) {
				LogHelper.v(TAG, "onServiceConnected. ILSWidgetService");
				loadLSWidgetList();
				startListeningLSWidgetService();
			}
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			LogHelper.v(TAG, "onServiceDisconnected. ILSWidgetService");
			mService = null;
		}
	}

	class Callbacks extends ILSWidgetCallback.Stub {

		@Override
		public void updateLSWidget(RemoteViews remoteViews, int viewType,
				boolean hasContent) throws RemoteException {
			LockscreenViewData data = mLockscreenViewList.get(viewType);
			LogHelper.d(TAG, "***************** updateLSWidget(),RemoteView id: " + remoteViews);
//			LogHelper.d(TAG, "********************** updateLSWidget. callback from LSWidgetService. null != data : " + (null != data));
			if (null != data) {
				data.data = remoteViews;
				data.hasContent = hasContent;
			}
			Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
			msg.arg1 = viewType;
			msg.sendToTarget();
		}

	}

	class UpdateHanlder extends Handler {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case HANDLE_READY:
				connectLSWidgetService();
				break;
			case HANDLE_ADD:
				addLSWidgetView();
				break;
			case HANDLE_UPDATE:
				updateLSWidgetView(msg.arg1);
				break;
			default:
				break;
			}
		}
	}
}
